package com.zjtx.tech.demo.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class GeoPointGenerator {

    // 地球平均半径，单位：千米
    private static final double EARTH_RADIUS_KM = 6371;
    private static final Random RANDOM = new Random();

    /**
     * 生成指定数量的经纬度信息，满足特定的距离条件。
     *
     * @param centerLongitude 中心点的经度
     * @param centerLatitude  中心点的纬度
     * @return 生成的经纬度列表
     */
    public static List<Double[]> generateGeoPoints(double centerLongitude, double centerLatitude) {
        List<Double[]> geoPoints = new ArrayList<>();
        // 不足1km, 不足2km, 不足3km, 超过3km 的数量
        int[] counts = {2, 3, 4, 3};
        // 距离上限
        double[] distancesKm = {1, 2, 3, 10};

        for (int i = 0; i < counts.length; i++) {
            for (int j = 0; j < counts[i]; j++) {
                double distanceKm = getRandomDistance(distancesKm[i]);
                double angle = getRandomAngle();
                Double[] point = getGeoPoint(centerLongitude, centerLatitude, distanceKm, angle);
                while (point[0] < 0 || point[1] < 0) {
                    // 如果生成的经纬度有负值，则重新生成
                    distanceKm = getRandomDistance(distancesKm[i]);
                    angle = getRandomAngle();
                    point = getGeoPoint(centerLongitude, centerLatitude, distanceKm, angle);
                }
                geoPoints.add(point);
            }
        }

        return geoPoints;
    }

    private static double getRandomDistance(double maxDistanceKm) {
        return RANDOM.nextDouble() * maxDistanceKm;
    }

    private static double getRandomAngle() {
        return RANDOM.nextDouble() * 360;
    }

    private static Double[] getGeoPoint(double centerLongitude, double centerLatitude, double distanceKm, double angleDegrees) {
        // 将角度转换为弧度
        double angle = Math.toRadians(angleDegrees);
        // 计算半径
        double radius = distanceKm / EARTH_RADIUS_KM;
        double lat1 = Math.toRadians(centerLatitude);
        double lon1 = Math.toRadians(centerLongitude);
        double lat2 = Math.asin(Math.sin(lat1) * Math.cos(radius) + Math.cos(lat1) * Math.sin(radius) * Math.cos(angle));
        double lon2 = lon1 + Math.atan2(Math.sin(angle) * Math.sin(radius) * Math.cos(lat1), Math.cos(radius) - Math.sin(lat1) * Math.sin(lat2));
        return new Double[]{Math.toDegrees(lon2), Math.toDegrees(lat2)};
    }

}
